<?php
/**
 * Copyright 2011  SURFfoundation
 * 
 * This file is part of ESCAPE.
 * 
 * ESCAPE is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ESCAPE is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ESCAPE.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For more information:
 * http://escapesurf.wordpress.com/
 * http://www.surffoundation.nl/
 * 
 * Contact: d.vierkant@utwente.nl
 * 
 * @license http://www.gnu.org/licenses/gpl.html GNU GPLv3
 */
?>
<?php
/**
 * Repository schema
 * 
 * Extends the RDF Schema Document with Escape specific methods.
 */
class escape_rdf_RepositorySchemaDocument extends simplerdf_RdfSchemaDocument
{
	/**
	 * Construct a new escape_rdf_RepositorySchemaDocument.
	 * @param string|array $rdfXmlOrSimpleIndex Either a string containing a RDF/XML document or an ARC2 SimpleIndex
	 * @param escape_rdf_RepositorySchemaDocument $schema RDF Schema (optional)
	 * @param string $base XML base URL (optional)
	 */
	public function __construct($rdfXmlOrSimpleIndex, &$schema = null, $base = '')
	{
		parent::__construct($rdfXmlOrSimpleIndex, $schema, $base);
	}
	
	/**
	 * Create a new (empty) document.
	 * @param string $subject The subject of the resource 
	 * @param escape_rdf_RepositorySchemaDocument $schema RDF Schema (optional)
	 * @return escape_rdf_RepositorySchemaDocument The new (empty) resource
	 */
	public static function createRepositorySchemaDocument(&$schema = null)
	{
		$index = array();
		
		return new self($index, $schema);
	}
	
	/**
	 * Get the plural version of the rdfs:label of a schema resource.
	 * First the predicate http://purl.utwente.nl/ns/escape-system.owl#labelPlural is checked, if it doesn't exist the rdfs:label is used with a 's' appended to the end.
	 * @param string $resourceUri Resource URI
	 * @param string $returnUriIfNotFound If true, the resource URI is returned if the resource does not have a label, otherwise a null will be returned
	 * @return string Plural resource label
	 */
	public function getResourceLabelPlural($resourceUri, $returnUriIfNotFound = true)
	{
		$label = null;
		
		$resource = $this->getResourceBySubject($resourceUri);
		if($resource !== null)
		{
			$label = $resource->getFirstObject('http://purl.utwente.nl/ns/escape-system.owl#labelPlural');
			if($label === null)
			{
				$label = $this->getResourceLabel($resourceUri, true);
				if($label !== null)
				{
					$label .= 's';
				}
			}
		}

		if($label === null && $returnUriIfNotFound)
		{
			$label = $resourceUri;
		}
		
		return $label;
	}

	/**
	 * Get the objects for the specified classes and predicate (including parent classes).
	 * @param array|string $classUris Class URI(s)
	 * @param string $predicate Predicate URI
	 * @param boolean $useInheritance If true, objects from parent classes are also included
	 * @return array Objects
	 */
	public function getClassPropertyObjectList($classUris, $predicate, $useInheritance = true)
	{
		$classPropertyObjectList = array();
		
		if(!is_array($classUris))
		{
			$classUris = array($classUris);
		}

		if($useInheritance)
		{
			$classUrisWithInheritance = array();
			foreach($classUris as $classUri)
			{
				$classUrisWithInheritance[] = $classUri;
				$parentClassUris = $this->getParentClassUriList($classUri);
				foreach($parentClassUris as $parentClassUri)
				{
					$classUrisWithInheritance[] = $parentClassUri;
				}
			}
			$classUris = array_reverse($classUris);
			$classUris = array_unique($classUrisWithInheritance);
		}
		
		foreach($classUris as $classUri)
		{
			$rdfResource = $this->getResourceBySubject($classUri);
			if($rdfResource !== null)
			{
				$objects = $rdfResource->getObjects($predicate);
				foreach($objects as $object)
				{
					$classPropertyObjectList[] = $object;
				}
			}
		}
		
		$classPropertyObjectList = array_unique($classPropertyObjectList);
		
		return $classPropertyObjectList;
	}
	
	/**
	 * Get a list of properties allowed for the class specified, based on 'owl:Restriction'.
	 * @param array|string $classUris Class URI(s)
	 * @param boolean $useInheritance If true, allowed properties from parent classes are also included
	 * @return array Array, keys containing property URI strings, values containing arrays with the keys 'minCardinality' and 'maxCardinality' based on 'owl:cardinality', 'owl:minCardinality' and 'owl:maxCardinality'
	 */
	public function getAllowedClassPropertyListWithDetails($classUris, $useInheritance = true)
	{
		$classPropertyUriList = array();
		
		if(!is_array($classUris))
		{
			$classUris = array($classUris);
		}
		
		foreach($classUris as $classUri)
		{
			if($useInheritance)
			{
				$parentClassUris = $this->getParentClassUris($classUri);
				if(count($parentClassUris) > 0)
				{
					$parentClassPropertyUriList = $this->getAllowedClassPropertyListWithDetails($parentClassUris, true);
					foreach($parentClassPropertyUriList as $parentClassPropertyUri => $parentClassPropertyDetails)
					{
						$classPropertyUriList[$parentClassPropertyUri] = $parentClassPropertyDetails;
					}
				}
			}
			
			$classRdfResource = $this->getResourceBySubject($classUri);
			if($classRdfResource !== null)
			{
				$parentClassUris = $classRdfResource->getObjects('http://www.w3.org/2000/01/rdf-schema#subClassOf');
				foreach($parentClassUris as $parentClassUri)
				{
					// only follow blank nodes
					if(preg_match('/^_:/', $parentClassUri))
					{
						$blankNodeRdfResource = $this->getResourceBySubject($parentClassUri);
						if($blankNodeRdfResource->hasRdfType('http://www.w3.org/2002/07/owl#Restriction'));
						{
							// this is an owl:restriction
							$onProperty = $blankNodeRdfResource->getFirstObject('http://www.w3.org/2002/07/owl#onProperty');
							if($onProperty !== null)
							{
								$cardinality = $blankNodeRdfResource->getFirstObject('http://www.w3.org/2002/07/owl#cardinality');
								$minCardinality = $blankNodeRdfResource->getFirstObject('http://www.w3.org/2002/07/owl#minCardinality');
								$maxCardinality = $blankNodeRdfResource->getFirstObject('http://www.w3.org/2002/07/owl#maxCardinality');
								if($cardinality !== null)
								{
									$minCardinality = $cardinality;
									$maxCardinality = $cardinality;
								}
								
								$classPropertyUriList[$onProperty] = array(
																			'minCardinality' => $minCardinality,
																			'maxCardinality' => $maxCardinality,
																		);
							}
						}
					}
				}
			} 
		}
		
		return $classPropertyUriList;
//		return $this->getClassPropertyObjectList($classUris, "http://purl.utwente.nl/ns/escape-system.owl#hasProperty", $useInheritance);
	}

	/**
	 * Get a list of title property URIs for the class specified.
	 * @param array|string $classUris Class URI(s)
	 * @param boolean $useInheritance If true, title properties from parent classes are also included
	 * @return array property URIs
	 */
	public function getClassTitlePropertyUriList($classUris, $useInheritance = true)
	{
		return $this->getClassPropertyObjectList($classUris, "http://purl.utwente.nl/ns/escape-system.owl#hasTitleProperty", $useInheritance);
	}

	/**
	 * Get a list of short view property URIs for the class specified.
	 * @param array|string $classUris Class URI(s)
	 * @param boolean $useInheritance If true, short view properties from parent classes are also included
	 * @return array property URIs
	 */
	public function getClassShortViewPropertyUriList($classUris, $useInheritance = true)
	{
		return $this->getClassPropertyObjectList($classUris, "http://purl.utwente.nl/ns/escape-system.owl#hasShortViewProperty", $useInheritance);
	}

	/**
	 * Check if the property specified is a escape-system:NonAssignableProperty, escape-system:HiddenProperty or escape-system:SystemProperty.
	 * @param string $propertyUri Property URI 
	 * @return boolean True if the property specified has the RDF type escape-system:NonAssignableProperty, escape-system:HiddenProperty or escape-system:SystemProperty
	 */
	public function isNonAssignableProperty($propertyUri)
	{
		$isNonAssignableProperty = false;
		
		$resource = $this->getResourceBySubject($propertyUri);
		if($resource !== null)
		{
			$isNonAssignableProperty = $resource->hasRdfType("http://purl.utwente.nl/ns/escape-system.owl#NonAssignableProperty");
			if($isNonAssignableProperty === false)
			{
				$isNonAssignableProperty = $resource->hasRdfType('http://purl.utwente.nl/ns/escape-system.owl#HiddenProperty');
				if($isNonAssignableProperty === false)
				{
					$isNonAssignableProperty = $resource->hasRdfType('http://purl.utwente.nl/ns/escape-system.owl#SystemProperty');
				}
			}
		}
		
		return $isNonAssignableProperty;
	}
	
	/**
	 * Check if the property specified is a escape-system:HiddenProperty or escape-system:SystemProperty.
	 * @param string $propertyUri Property URI 
	 * @return boolean True if the property specified has the RDF type escape-system:HiddenProperty or escape-system:SystemProperty
	 */
	public function isHiddenProperty($propertyUri)
	{
		$isHiddenProperty = false;
		
		$resource = $this->getResourceBySubject($propertyUri);
		if($resource !== null)
		{
			$isHiddenProperty = $resource->hasRdfType('http://purl.utwente.nl/ns/escape-system.owl#HiddenProperty');
			if($isHiddenProperty === false)
			{
				$isHiddenProperty = $resource->hasRdfType('http://purl.utwente.nl/ns/escape-system.owl#SystemProperty');
			}
		}
		
		return $isHiddenProperty;
	}
	
	/**
	 * Check if the property specified is a escape-system:SystemProperty.
	 * @param string $propertyUri Property URI 
	 * @return boolean True if the property specified has the RDF type escape-system:SystemProperty
	 */
	public function isSystemProperty($propertyUri)
	{
		$isSystemProperty = false;
		
		$resource = $this->getResourceBySubject($propertyUri);
		if($resource !== null)
		{
			$isSystemProperty = $resource->hasRdfType('http://purl.utwente.nl/ns/escape-system.owl#SystemProperty');
		}
		
		return $isSystemProperty;
	}
	
	/**
	 * Check if the class specified is a escape-system:SystemClass.
	 * @param string $classUri Class URI 
	 * @return boolean True if the class specified has the RDF type escape-system:SystemClass
	 */
	public function isSystemClass($classUri)
	{
		$isSystemClass = false;
		
		$resource = $this->getResourceBySubject($classUri);
		if($resource !== null)
		{
			$isSystemClass = $resource->hasRdfType('http://purl.utwente.nl/ns/escape-system.owl#SystemClass');
		}
		
		return $isSystemClass;
	}
	
	/**
	 * Get the ESCAPE root class URI of the class specified (class on top of the inheritance chain just before an escape-system:Thing parent class, not necessarily the root class of the full chain).
	 * @param string $classUri Class URI 
	 * @return string ESCAPE root class URI of the class specified
	 */
	public function getEscapeRootClassUri($classUri)
	{
		$escapeRootClassUri = null;
		
		$parentClassUris = $this->getParentClassUris($classUri);
		foreach($parentClassUris as $parentClassUri)
		{
			if($parentClassUri === 'http://purl.utwente.nl/ns/escape-system.owl#Thing')
			{
				$escapeRootClassUri = $classUri;
				break;
			}
			else
			{
				$escapeRootClassUri = $this->getEscapeRootClassUri($parentClassUri);
				if($escapeRootClassUri !== null)
				{
					break;
				}
			}
		}
		
		return $escapeRootClassUri;
	}

	/**
	 * Get a list of non-system parent property URIs.
	 * @param string $propertyUri Property URI 
	 * @return array list of non-system parent property URIs
	 */
/*TODO not used, delete?
	public function getNonSystemParentPropertyUriList($propertyUri)
	{
		$nonSystemParentPropertyUris = array();
		
		$parentPropertyUris = $this->getParentPropertyUriList($propertyUri);
		foreach($parentPropertyUris as $parentPropertyUri)
		{
			if($this->isSystemProperty($parentPropertyUri))
			{
				break;
			}
			$nonSystemParentPropertyUris[] = $parentPropertyUri;
		}
		
		return $nonSystemParentPropertyUris;
	}
*/

	/**
	 * Get the non-system root property URI of the property specified.
	 * @param string $propertyUri Property URI 
	 * @return string non-system root property URI of the property specified
	 */
/*TODO not used, delete?
	public function getNonSystemRootPropertyUri($propertyUri)
	{
		$nonSystemRootPropertyUri = $propertyUri;
		
		$parentPropertyUris = $this->getParentPropertyUriList($propertyUri);
		foreach($parentPropertyUris as $parentPropertyUri)
		{
			if($this->isSystemProperty($parentPropertyUri))
			{
				break;
			}
			$nonSystemRootPropertyUri = $parentPropertyUri;
		}
		
		return $nonSystemRootPropertyUri;
	}
*/
	
	/**
	 * Get a list of assignable sub properties (without the RDF type escape-system:NonAssignableProperty).
	 * @param string $propertyUri Property URI 
	 * @return array List of assignable sub properties
	 */
	public function getAssignableSubPropertyUriList($propertyUri)
	{
		return $this->getChainedObjectSubjectsList('http://www.w3.org/2000/01/rdf-schema#subPropertyOf', $propertyUri, null, array('http://www.w3.org/1999/02/22-rdf-syntax-ns#type' => 'http://purl.utwente.nl/ns/escape-system.owl#NonAssignableProperty'));
	}
	
	/**
	 * Get a list of assignable sub properties in tree form (without the RDF type escape-system:NonAssignableProperty).
	 * @param string $propertyUri Property URI 
	 * @return array List of assignable sub properties in tree form
	 */
	public function getAssignableSubPropertyUriTree($propertyUri)
	{
		return $this->getChainedObjectSubjectsTree('http://www.w3.org/2000/01/rdf-schema#subPropertyOf', $propertyUri, null, array('http://www.w3.org/1999/02/22-rdf-syntax-ns#type' => 'http://purl.utwente.nl/ns/escape-system.owl#NonAssignableProperty'));
	}
}
